﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using iNet.IO;
using iNet.Net;
using iNet.Tasks;

namespace iNet.Media
{
	/// <summary>
	/// 媒體相關工作的基底類別。
	/// </summary>
	public abstract class MediaTask : Task
	{
		#region 欄位
		volatile Dictionary<MediaStorage, List<string>> _CreatedTempFiles;
		volatile List<Stream> _CreatedTempStreams;
		volatile Dictionary<Stream, WebResponse> _CreatedWebResponses;
		volatile Dictionary<Stream, long> _StreamInitialPositions;
		#endregion
		#region 建構子
		/// <summary>
		/// 初始化新的 MediaTask 執行個體。
		/// </summary>
		protected MediaTask()
		{ }
		#endregion
		#region AddTempFilePath
		void AddTempFilePath(MediaStorage storage, string filePath)
		{
			if (_CreatedTempFiles == null)
				_CreatedTempFiles = new Dictionary<MediaStorage, List<string>>();
			List<string> pathList;
			if (!_CreatedTempFiles.TryGetValue(storage, out pathList))
			{
				pathList = new List<string>();
				_CreatedTempFiles[storage] = pathList;
			}
			pathList.Add(filePath);
		}
		#endregion
		#region CommitToMediaStorage
		/// <summary>
		/// 確保修改過的媒體儲存檔案寫入媒體儲存。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="storage">指定的媒體儲存。</param>
		/// <param name="progressRange">寫入資料時的工作進度變化範圍，零或負值表示進度不需要變化。</param>
		/// <param name="filePath">存放媒體資料的檔案路徑。</param>
		/// <returns>True 表示成功將資料寫入媒體儲存，False 表示失敗或工作已取消。</returns>
		/// <exception cref="ArgumentNullException">version、storage 或 filePath 為 Null (Visual Basic 為 Nothing)。</exception>
		/// <exception cref="ArgumentException">filePath 為無效檔案路徑。</exception>
		protected bool CommitToMediaStorage(TaskVersion version, MediaStorage storage, double progressRange, string filePath)
		{
			//確認參數
			if (version == null)
				throw new ArgumentNullException("version");
			if (storage == null)
				throw new ArgumentNullException("storage");
			if (filePath == null)
				throw new ArgumentNullException("filePath");
			if (!FileUtility.IsValidPath(filePath))
				throw new ArgumentException();

			//確認工作版本
			if (this.CurrentVersion != version)
				return false;

			//輸出至媒體儲存
			try
			{
				switch (storage.StorageType)
				{
					case MediaStorageType.File:
						if (!PathComparer.Default.Equals(storage.FileName, filePath))
						{
							FileCopyTask copyTask = new FileCopyTask(filePath, storage.FileName);
							if (progressRange > 0)
							{
								copyTask.ProgressChanged += (send, e) =>
								{
									double? progress = (this.Progress.GetValueOrDefault() + (progressRange * e.Progress / 100));
									this.ReportProgress(version, progress);
								};
							}
							return (this.ExecuteChildTask(version, copyTask) == TaskState.Executed);
						}
						return true;
					case MediaStorageType.Stream:
						{
							//取得目的資料流
							Stream stream = storage.Stream;
							long originalStreamPosition;
							try
							{
								if (!stream.CanWrite)
									return false;
								originalStreamPosition = (stream.CanSeek ? stream.Position : -1);
							}
							catch
							{
								originalStreamPosition = -1;
							}

							//複製資料至資料流
							try
							{
								using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
								{
									StreamCopyTask copyTask = new StreamCopyTask(fileStream, stream);
									if (progressRange > 0)
									{
										copyTask.ProgressChanged += (send, e) =>
										{
											double? progress = (this.Progress.GetValueOrDefault() + (progressRange * e.Progress / 100));
											this.ReportProgress(version, progress);
										};
									}
									if (this.ExecuteChildTask(version, copyTask) != TaskState.Executed)
										return false;
								}
								return true;
							}
							catch
							{
								return false;
							}
							finally
							{
								//恢復資料流位置
								if (originalStreamPosition >= 0)
								{
									try
									{
										stream.Position = originalStreamPosition;
									}
									catch
									{ }
								}
							}
						}
					case MediaStorageType.Uri:
					case MediaStorageType.WebRequest:
						{
							//建立上傳工作
							FileUploadTask uploadTask = new FileUploadTask();
							uploadTask.SourceFilePath = filePath;
							if (storage.StorageType == MediaStorageType.Uri)
								uploadTask.UploadUri = storage.Uri;
							else
							{
								WebRequest request = storage.WebRequest;
								uploadTask.Credentials = request.Credentials;
								uploadTask.Headers = request.Headers;
								uploadTask.Method = request.Method;
								uploadTask.Proxy = request.Proxy;
								uploadTask.UploadUri = request.RequestUri;
							}
							if (progressRange > 0)
							{
								uploadTask.ProgressChanged += (send, e) =>
								{
									double? progress = (this.Progress.GetValueOrDefault() + (progressRange * e.Progress / 100));
									this.ReportProgress(version, progress);
								};
							}

							//上傳檔案
							return (this.ExecuteChildTask(version, uploadTask) == TaskState.Executed);
						}
					default:
						return false;
				}
			}
			finally
			{
				//更新進度
				if (progressRange > 0)
				{
					double progress = (this.Progress.GetValueOrDefault() + progressRange);
					this.ReportProgress(version, progress);
				}
			}
		}
		/// <summary>
		/// 確保修改過的媒體儲存資料流寫入媒體儲存。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="storage">指定的媒體儲存。</param>
		/// <param name="progressRange">寫入資料時的工作進度變化範圍，零或負值表示進度不需要變化。</param>
		/// <param name="stream">存放媒體資料的資料流。</param>
		/// <returns>True 表示成功將資料寫入媒體儲存，False 表示失敗或工作已取消。</returns>
		/// <exception cref="ArgumentNullException">version、storage 或 stream 為 Null (Visual Basic 為 Nothing)。</exception>
		protected bool CommitToMediaStorage(TaskVersion version, MediaStorage storage, double progressRange, Stream stream)
		{
			//確認參數
			if (version == null)
				throw new ArgumentNullException("version");
			if (storage == null)
				throw new ArgumentNullException("storage");
			if (stream == null)
				throw new ArgumentNullException("stream");

			//輸出至媒體儲存
			long currentPosition = -1;
			try
			{
				//取得目前資料流位置
				try
				{
					currentPosition = stream.Position;
				}
				catch
				{ }

				//恢復資料流位置
				lock (this.SyncRoot)
				{
					long initialPosition;
					if (_StreamInitialPositions != null && _StreamInitialPositions.TryGetValue(stream, out initialPosition))
						stream.Position = initialPosition;
				}

				//輸出至媒體儲存
				switch (storage.StorageType)
				{
					case MediaStorageType.Stream:
						{
							Stream originalStream = storage.Stream;
							if (originalStream != stream)
							{
								//確認目標執行緒
								if (!originalStream.CanWrite)
									return false;

								//複製至目標資料流
								StreamCopyTask copyTask = new StreamCopyTask(stream, originalStream);
								if (progressRange > 0)
								{
									copyTask.ProgressChanged += (send, e) =>
									{
										double? progress = (this.Progress.GetValueOrDefault() + (progressRange * e.Progress / 100));
										this.ReportProgress(version, progress);
									};
								}
								if (this.ExecuteChildTask(version, copyTask) != TaskState.Executed)
									return false;
							}
							else if (currentPosition >= 0)
								stream.Position = currentPosition;
							return true;
						}
					case MediaStorageType.File:
						{
							try
							{
								//取得目標檔案路徑
								string filePath = storage.FileName;
								FileStream fileStream = (stream as FileStream);
								if (fileStream != null && PathComparer.Default.Equals(fileStream.Name, filePath))
								{
									stream.Position = stream.Length;
									return true;
								}

								//將資料寫入目標檔案
								using (FileStream targetStream = new FileStream(filePath, FileMode.Append, FileAccess.Write))
								{
									StreamCopyTask copyTask = new StreamCopyTask(stream, targetStream);
									if (progressRange > 0)
									{
										copyTask.ProgressChanged += (send, e) =>
										{
											double? progress = (this.Progress.GetValueOrDefault() + (progressRange * e.Progress / 100));
											this.ReportProgress(version, progress);
										};
									}
									if (this.ExecuteChildTask(version, copyTask) != TaskState.Executed)
										return false;
									return true;
								}
							}
							catch
							{
								return false;
							}
						}
					case MediaStorageType.Uri:
					case MediaStorageType.WebRequest:
						{
							//建立上傳工作
							FileUploadTask uploadTask = new FileUploadTask();
							uploadTask.SourceStream = stream;
							if (storage.StorageType == MediaStorageType.Uri)
								uploadTask.UploadUri = storage.Uri;
							else
							{
								WebRequest request = storage.WebRequest;
								uploadTask.Credentials = request.Credentials;
								uploadTask.Headers = request.Headers;
								uploadTask.Method = request.Method;
								uploadTask.Proxy = request.Proxy;
								uploadTask.UploadUri = request.RequestUri;
							}
							if (progressRange > 0)
							{
								uploadTask.ProgressChanged += (send, e) =>
								{
									double? progress = (this.Progress.GetValueOrDefault() + (progressRange * e.Progress / 100));
									this.ReportProgress(version, progress);
								};
							}

							//上傳檔案
							return (this.ExecuteChildTask(version, uploadTask) == TaskState.Executed);
						}
					default:
						return false;
				}
			}
			finally
			{
				//儲存資料流位置
				if (currentPosition >= 0)
				{
					lock (this.SyncRoot)
					{
						if (_StreamInitialPositions == null)
							_StreamInitialPositions = new Dictionary<Stream, long>();
						_StreamInitialPositions[stream] = currentPosition;
					}
				}

				//更新進度
				if (progressRange > 0)
				{
					double progress = (this.Progress.GetValueOrDefault() + progressRange);
					this.ReportProgress(version, progress);
				}
			}
		}
		#endregion
		#region GetMediaStorageFile
		/// <summary>
		/// 取得代表指定媒體儲存的檔案，若媒體儲存不是檔案則建立暫存檔。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="storage">指定的媒體儲存。</param>
		/// <param name="progressRange">取得檔案時的工作進度變化範圍，零或負值表示進度不需要變化。</param>
		/// <param name="filePath">代表指定媒體儲存的檔案路徑。</param>
		/// <returns>True 表示成功取得檔案，False 表示失敗或工作已取消。</returns>
		/// <exception cref="ArgumentNullException">version 或 storage 為 Null (Visual Basic 為 Nothing)。</exception>
		protected bool GetMediaStorageFile(TaskVersion version, MediaStorage storage, double progressRange, out string filePath)
		{
			return this.GetMediaStorageFile(version, storage, 0, progressRange, out filePath);
		}
		/// <summary>
		/// 取得代表指定媒體儲存的檔案，若媒體儲存不是檔案則建立暫存檔。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="storage">指定的媒體儲存。</param>
		/// <param name="flags">媒體儲存檔案的旗標組合。</param>
		/// <param name="progressRange">取得檔案時的工作進度變化範圍，零或負值表示進度不需要變化。</param>
		/// <param name="filePath">代表指定媒體儲存的檔案路徑。</param>
		/// <returns>True 表示成功取得檔案，False 表示失敗或工作已取消。</returns>
		/// <exception cref="ArgumentNullException">version 或 storage 為 Null (Visual Basic 為 Nothing)。</exception>
		protected bool GetMediaStorageFile(TaskVersion version, MediaStorage storage, MediaStorageFileFlags flags, double progressRange, out string filePath)
		{
			//確認參數
			if (version == null)
				throw new ArgumentNullException("version");
			if (storage == null)
				throw new ArgumentNullException("storage");

			//確認工作版本
			filePath = null;
			if (this.CurrentVersion != version)
				return false;

			//轉換成為檔案
			try
			{
				switch (storage.StorageType)
				{
					case MediaStorageType.File:
						{
							//取得檔案路徑
							filePath = storage.FileName;

							//確認檔案路徑
							if ((flags & MediaStorageFileFlags.AnsiFilePathOnly) != 0 && filePath.HasNonAnsiChar())
							{
								//建立暫存檔
								filePath = null;
								try
								{
									filePath = Path.GetTempFileName() + Path.GetExtension(filePath);
								}
								catch
								{
									return false;
								}

								//複製檔案
								FileCopyTask copyTask = new FileCopyTask(storage.FileName, filePath);
								if (progressRange > 0)
								{
									copyTask.ProgressChanged += (send, e) =>
									{
										double? progress = (this.Progress.GetValueOrDefault() + (progressRange * e.Progress / 100));
										this.ReportProgress(version, progress);
									};
								}
								if (this.ExecuteChildTask(version, copyTask) != TaskState.Executed)
								{
									File.Delete(filePath);
									filePath = null;
									return false;
								}
								lock (this.SyncRoot)
								{
									this.AddTempFilePath(storage, filePath);
								}
							}
							return true;
						}
					case MediaStorageType.Stream:
						{
							//取得來源資料流
							Stream stream = storage.Stream;
							long originalStreamPosition;
							try
							{
								originalStreamPosition = (stream.CanSeek ? stream.Position : -1);
							}
							catch
							{
								originalStreamPosition = -1;
							}

							//建立暫存檔
							try
							{
								filePath = Path.GetTempFileName();
								FileStream fileStream = (stream as FileStream);
								if (fileStream != null)
									filePath += Path.GetExtension(fileStream.Name);
							}
							catch
							{
								return false;
							}

							//複製資料至暫存檔案
							bool deleteTempFile = false;
							try
							{
								using (FileStream fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
								{
									StreamCopyTask copyTask = new StreamCopyTask(stream, fileStream);
									if (progressRange > 0)
									{
										copyTask.ProgressChanged += (send, e) =>
										{
											double? progress = (this.Progress.GetValueOrDefault() + (progressRange * e.Progress / 100));
											this.ReportProgress(version, progress);
										};
									}
									if (this.ExecuteChildTask(version, copyTask) != TaskState.Executed)
									{
										deleteTempFile = true;
										return false;
									}
								}
								return true;
							}
							catch
							{
								deleteTempFile = true;
								return false;
							}
							finally
							{
								//恢復資料流位置
								if (originalStreamPosition >= 0)
								{
									try
									{
										stream.Position = originalStreamPosition;
									}
									catch
									{ }
								}

								//刪除暫存檔
								if (deleteTempFile)
								{
									File.Delete(filePath);
									filePath = null;
								}
								else
								{
									lock (this.SyncRoot)
									{
										this.AddTempFilePath(storage, filePath);
									}
								}
							}
						}
					case MediaStorageType.Uri:
					case MediaStorageType.WebRequest:
						{
							//建立下載工作
							WebDocumentDownloadTask downloadTask = new WebDocumentDownloadTask();
							if (storage.StorageType == MediaStorageType.WebRequest)
								downloadTask.Request = storage.WebRequest;
							else
							{
								try
								{
									downloadTask.Request = WebRequest.Create(storage.Uri);
								}
								catch
								{
									return false;
								}
							}
							if (progressRange > 0)
							{
								downloadTask.ProgressChanged += (send, e) =>
								{
									double? progress = (this.Progress.GetValueOrDefault() + (progressRange * e.Progress / 100));
									this.ReportProgress(version, progress);
								};
							}

							//建立暫存檔
							try
							{
								filePath = Path.GetTempFileName() + Path.GetExtension(downloadTask.Request.RequestUri.AbsolutePath);
							}
							catch
							{
								return false;
							}
							downloadTask.LocalFileName = filePath;

							//下載至檔案
							if (this.ExecuteChildTask(version, downloadTask) != TaskState.Executed)
							{
								File.Delete(filePath);
								filePath = null;
								return false;
							}
							lock (this.SyncRoot)
							{
								this.AddTempFilePath(storage, filePath);
							}
							return true;
						}
					default:
						return false;
				}
			}
			finally
			{
				//更新進度
				if (progressRange > 0)
				{
					double progress = (this.Progress.GetValueOrDefault() + progressRange);
					this.ReportProgress(version, progress);
				}
			}
		}
		#endregion
		#region GetMediaStorageStream
		/// <summary>
		/// 取得存取指定媒體儲存的資料流。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="storage">指定的媒體儲存。</param>
		/// <param name="progressRange">取得資料流時的工作進度變化範圍，零或負值表示進度不需要變化。</param>
		/// <param name="stream">取得的媒體儲存資料流。</param>
		/// <returns>True 表示成功取得資料流，False 表示失敗或工作已取消。</returns>
		/// <exception cref="ArgumentNullException">version 或 storage 為 Null (Visual Basic 為 Nothing)。</exception>
		protected bool GetMediaStorageStream(TaskVersion version, MediaStorage storage, double progressRange, out Stream stream)
		{
			return this.GetMediaStorageStream(version, storage, MediaStorageStreamFlags.Readable | MediaStorageStreamFlags.Seekable | MediaStorageStreamFlags.Writable, progressRange, out stream);
		}
		/// <summary>
		/// 取得存取指定媒體儲存的資料流。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="storage">指定的媒體儲存。</param>
		/// <param name="flags">媒體儲存資料流的旗標組合。</param>
		/// <param name="progressRange">取得資料流時的工作進度變化範圍，零或負值表示進度不需要變化。</param>
		/// <param name="stream">取得的媒體儲存資料流。</param>
		/// <returns>True 表示成功取得資料流，False 表示失敗或工作已取消。</returns>
		/// <exception cref="ArgumentNullException">version 或 storage 為 Null (Visual Basic 為 Nothing)。</exception>
		protected bool GetMediaStorageStream(TaskVersion version, MediaStorage storage, MediaStorageStreamFlags flags, double progressRange, out Stream stream)
		{
			//確認參數
			if (version == null)
				throw new ArgumentNullException("version");
			if (storage == null)
				throw new ArgumentNullException("storage");

			//確認工作版本
			stream = null;
			if (this.CurrentVersion != version)
				return false;

			//取得資料流
			try
			{
				switch (storage.StorageType)
				{
					case MediaStorageType.Stream:
						{
							//取得資料流
							stream = storage.Stream;

							//確認資料流
							if (((flags & MediaStorageStreamFlags.Readable) != 0 && !stream.CanRead)
								|| ((flags & MediaStorageStreamFlags.Writable) != 0 && !stream.CanWrite)
								|| ((flags & MediaStorageStreamFlags.Seekable) != 0 && !stream.CanSeek))
							{
								//建立暫存檔
								string tempFilePath;
								if (!this.GetMediaStorageFile(version, storage, progressRange, out tempFilePath))
									return false;

								//開啟暫存檔
								try
								{
									stream = new FileStream(tempFilePath, FileMode.Open, FileAccess.ReadWrite);
									lock (this.SyncRoot)
									{
										if (_CreatedTempStreams == null)
											_CreatedTempStreams = new List<Stream>();
										_CreatedTempStreams.Add(stream);
									}
								}
								catch
								{
									stream = null;
									this.ReleaseMediaStorageFile(version, storage, tempFilePath);
									return false;
								}
							}

							//儲存資料流位置
							try
							{
								if (stream.CanSeek)
								{
									lock (this.SyncRoot)
									{
										if (_StreamInitialPositions == null)
											_StreamInitialPositions = new Dictionary<Stream, long>();
										_StreamInitialPositions[stream] = stream.Position;
									}
								}
							}
							catch
							{ }

							//完成
							return true;
						}
					case MediaStorageType.File:
						{
							//開啟檔案
							try
							{
								FileAccess access = 0;
								FileMode mode = FileMode.Open;
								if ((flags & MediaStorageStreamFlags.Readable) != 0)
									access |= FileAccess.Read;
								if ((flags & MediaStorageStreamFlags.Writable) != 0)
								{
									access |= FileAccess.Write;
									mode = FileMode.OpenOrCreate;
								}
								if (access == 0)
								{
									access = FileAccess.ReadWrite;
									mode = FileMode.OpenOrCreate;
								}
								int retryCount = 10;
								while (true)
								{
									try
									{
										stream = new FileStream(storage.FileName, mode, access, ((access & FileAccess.Write) == 0 ? FileShare.Read : FileShare.None));
										break;
									}
									catch
									{
										--retryCount;
										if (File.Exists(storage.FileName) && retryCount > 0 && !this.IsCanceling)
											System.Threading.Thread.Sleep(500);
										else
											return false;
									}
								}
								lock (this.SyncRoot)
								{
									if (_CreatedTempStreams == null)
										_CreatedTempStreams = new List<Stream>();
									if (_StreamInitialPositions == null)
										_StreamInitialPositions = new Dictionary<Stream, long>();
									_CreatedTempStreams.Add(stream);
									_StreamInitialPositions[stream] = 0;
								}
								return true;
							}
							catch
							{
								return false;
							}
						}
					case MediaStorageType.Uri:
					case MediaStorageType.WebRequest:
						if ((flags & (MediaStorageStreamFlags.Seekable | MediaStorageStreamFlags.Writable)) == 0)
						{
							//取得網路請求
							WebRequest request;
							if (storage.StorageType == MediaStorageType.WebRequest)
								request = storage.WebRequest;
							else
							{
								try
								{
									request = WebRequest.Create(storage.Uri);
								}
								catch
								{
									return false;
								}
							}

							//取得網路回應
							WebResponse response = null;
							if (!this.DoAction(new Action(() =>
							{
								response = request.GetResponse();
							}), System.Threading.Timeout.Infinite))
							{
								return false;
							}

							//開啟資料流
							if (response != null)
							{
								try
								{
									stream = response.GetResponseStream();
									lock (this.SyncRoot)
									{
										if (_CreatedTempStreams == null)
											_CreatedTempStreams = new List<Stream>();
										if (_CreatedWebResponses == null)
											_CreatedWebResponses = new Dictionary<Stream, WebResponse>();
										_CreatedTempStreams.Add(stream);
										_CreatedWebResponses[stream] = response;
									}
									return true;
								}
								catch
								{
									response.Close();
									return false;
								}
							}
							return false;
						}
						else
						{
							//建立暫存檔
							string tempFilePath;
							if (!this.GetMediaStorageFile(version, storage, progressRange, out tempFilePath))
								return false;

							//開啟暫存檔
							try
							{
								stream = new FileStream(tempFilePath, FileMode.Open, FileAccess.ReadWrite);
								lock (this.SyncRoot)
								{
									if (_CreatedTempStreams == null)
										_CreatedTempStreams = new List<Stream>();
									if (_StreamInitialPositions == null)
										_StreamInitialPositions = new Dictionary<Stream, long>();
									_CreatedTempStreams.Add(stream);
									_StreamInitialPositions[stream] = 0;
								}
								return true;
							}
							catch
							{
								stream = null;
								this.ReleaseMediaStorageFile(version, storage, tempFilePath);
								return false;
							}
						}
					default:
						return false;
				}
			}
			finally
			{
				//更新進度
				if (progressRange > 0)
				{
					double progress = (this.Progress.GetValueOrDefault() + progressRange);
					this.ReportProgress(version, progress);
				}
			}
		}
		#endregion
		#region ReleaseMediaStorageFile
		/// <summary>
		/// 釋放使用 GetMediaStorageFile 方法所取得的媒體儲存檔案。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="storage">指定的媒體儲存。</param>
		/// <param name="filePath">使用 GetMediaStorageFile 方法所取得的媒體儲存檔案路徑。</param>
		/// <exception cref="ArgumentNullException">version 或 storage 為 Null (Visual Basic 為 Nothing)。</exception>
		/// <exception cref="ArgumentException">filePath 為無效檔案路徑。</exception>
		protected void ReleaseMediaStorageFile(TaskVersion version, MediaStorage storage, string filePath)
		{
			//確認參數
			if (version == null)
				throw new ArgumentNullException("version");
			if (storage == null)
				throw new ArgumentNullException("storage");
			if (filePath == null)
				return;
			if (!FileUtility.IsValidPath(filePath))
				throw new ArgumentException();

			//確認是否為暫存檔案
			lock (this.SyncRoot)
			{
				List<string> tempFilePaths;
				if (_CreatedTempFiles == null
					|| !_CreatedTempFiles.TryGetValue(storage, out tempFilePaths)
					|| !tempFilePaths.Remove(filePath))
					return;
				if (tempFilePaths.Count == 0)
					_CreatedTempFiles.Remove(storage);
			}

			//刪除暫存檔案
			try
			{
				File.Delete(filePath);
			}
			catch
			{ }
		}
		#endregion
		#region ReleaseMediaStorageStream
		/// <summary>
		/// 釋放使用 GetMediaStorageStream 方法所取得的媒體儲存資料流。
		/// </summary>
		/// <param name="version">目前的工作版本。</param>
		/// <param name="storage">指定的媒體儲存。</param>
		/// <param name="stream">使用 GetMediaStorageStream 方法所取得的媒體儲存資料流。</param>
		/// <exception cref="ArgumentNullException">version 或 storage 為 Null (Visual Basic 為 Nothing)。</exception>
		protected void ReleaseMediaStorageStream(TaskVersion version, MediaStorage storage, Stream stream)
		{
			//確認參數
			if (version == null)
				throw new ArgumentNullException("version");
			if (storage == null)
				throw new ArgumentNullException("storage");
			if (stream == null)
				return;

			//釋放資料流
			lock (this.SyncRoot)
			{
				if (_CreatedTempStreams != null && _CreatedTempStreams.Remove(stream))
				{
					//關閉資料流
					stream.Close();

					//關閉網路回應
					WebResponse response;
					if (_CreatedWebResponses != null && _CreatedWebResponses.TryGetValue(stream, out response))
					{
						_CreatedWebResponses.Remove(stream);
						response.Close();
					}

					//釋放暫存檔
					FileStream fileStream = (stream as FileStream);
					if (fileStream != null)
						this.ReleaseMediaStorageFile(version, storage, fileStream.Name);
				}
			}
		}
		#endregion
	}

	#region MediaStorageFileFlags
	/// <summary>
	/// 表示媒體儲存檔案的旗標組合。
	/// </summary>
	[Flags]
	public enum MediaStorageFileFlags
	{
		/// <summary>
		/// 只支援 ANSI 檔案路徑。
		/// </summary>
		AnsiFilePathOnly = 0x1,
	}
	#endregion
	#region MediaStorageStreamFlags
	/// <summary>
	/// 表示媒體儲存資料流的旗標組合。
	/// </summary>
	[Flags]
	public enum MediaStorageStreamFlags
	{
		/// <summary>
		/// 確保資料流可以讀取。
		/// </summary>
		Readable = 0x1,
		/// <summary>
		/// 確保資料流可以寫入。
		/// </summary>
		Writable = 0x2,
		/// <summary>
		/// 確保資料流可以移動讀寫位置。
		/// </summary>
		Seekable = 0x4,
	}
	#endregion
}
